import time
import os
import pyodbc
import random
import pyautogui
from selenium.webdriver.chrome.webdriver import WebDriver

import screenshot
# import winrm
from faker import Faker
from selenium.webdriver.remote.webelement import WebElement
from selenium.common.exceptions import *
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium import webdriver
from logger import Logger
from config import get_cfg
from utils import get_date, parameter


class Base(object):
    """
    页面基础类，用于所有页面继承
    """

    logger = Logger('Base').get_log()
    # ip = get_cfg('server', 'ip')
    timeout = 30

    def __init__(self, selenium_driver=parameter['driver']):
        """
        构造

        :param selenium_driver: 谷歌driver
        :type selenium_driver: WebDriver
        """

        self.driver = selenium_driver
        # self.ip = Base.ip
        self.faker = Faker(locale='zh_CN')
        self.taxpayer_id = get_cfg('url', 'nsrsbh')
        self.project_id = get_cfg('project', 'project_id')

    # @staticmethod
    # def get_driver():
    #     # token = get_cfg('url', 'token')
    #     # user_info = '{"auto":"1         ","flag":"1","flag1":"1","readlog":"yidu","Rid1":0,' \
    #     #             '"UserName":"91131102588192882J","Zsxm":"","Rdes":"本单位的系统管理员","Nsrsbh":"91131102588192882J",' \
    #     #             '"Rname":"系统管理员","isHx":"0","Rid":90000092,"PassWord":"","Lsswjg":"1311027634",' \
    #     #             '"Version":"1.2.39","isSale":"-1","Nsrsbh1":"91131102588192882J",
    #     "Ocode":"91131102588192882J",' \
    #     #             '"IDUser":"90000093",' \
    #     #             '"token":"%s"}' % token
    #     header = get_cfg('header', 'headless')
    #     # js = 'window.localStorage.setItem("userInfo", \'{}\')'.format(user_info)
    #     if header == '1':
    #         # 启动谷歌无界面浏览器
    #         options = Options()
    #         options.add_argument('--headless')
    #         options.add_argument('--disable-gpu')
    #         driver = webdriver.Chrome(options=options)
    #     else:
    #         driver = webdriver.Chrome()
    #     return driver

    @staticmethod
    def get_random():
        """获取随机数"""
        return str(random.randint(1, 10000))

    @staticmethod
    def get_conn():
        """
        获取数据库连接

        :return: 数据库连接
        :rtype: pyodbc.Connection
        """
        server = get_cfg('db', 'server')
        db_driver = get_cfg('db', 'driver')
        dbname = get_cfg('db', 'database')
        user = get_cfg('db', 'user')
        pwd = get_cfg('db', 'pwd')
        db_driver = f'DRIVER={{{db_driver}}};SERVER={server};DATABASE={dbname};UID={user};PWD={pwd}'
        conn = pyodbc.connect(db_driver)
        return conn

    def find_element(self, locator, timeout=timeout):
        """
        查找单个元素

        :param timeout: 过期时间
        :type timeout: int
        :param locator: 元组
        :type locator: tuple
        :return: 查找到的元素
        :rtype: WebElement
        """

        return self.visibility_of_element(locator, timeout)

    def find_elements(self, locator, timeout=timeout):
        """
        查找多个元素

        :param timeout:
        :type timeout:
        :param locator: 元组
        :type locator: tuple
        :return: 查找到的元素
        :rtype:
        """
        self.presence_of_elements(locator, timeout)
        return self.driver.find_elements(*locator)

    def presence_of_element(self, locator, timeout=timeout):
        try:
            return WebDriverWait(self.driver, timeout).until(ec.presence_of_element_located(locator))
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(str(locator) + ': 元素不存在')

    def presence_of_elements(self, locator, timeout=timeout):
        try:
            return WebDriverWait(self.driver, timeout).until(ec.presence_of_all_elements_located(locator))
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(str(locator) + ': 元素不存在')

    def visibility_of_element(self, locator, timeout=timeout):
        try:
            return WebDriverWait(self.driver, timeout).until(ec.visibility_of_element_located(locator))
        except StaleElementReferenceException:
            return WebDriverWait(self.driver, timeout).until(ec.visibility_of_element_located(locator))
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(str(locator) + ': 元素不存在')

    def invisibility_of_element(self, locator, timeout=timeout):
        WebDriverWait(self.driver, timeout).until_not(ec.visibility_of_element_located(locator))

    def element_to_be_clickable(self, locator, timeout=timeout):
        try:
            return WebDriverWait(self.driver, timeout).until(ec.element_to_be_clickable(locator))
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(str(locator) + ': 元素不存在')

    def text_to_be_present_in_value(self, locator, value, timeout=timeout):
        """
        判断字符串是否在value中

        :param timeout: 超时时间
        :type timeout: int
        :param locator: 例如：(By.ID, 'id')
        :type locator: tuple
        :param value: 要判断的字符串
        :type value: str
        :return: 是或否
        :rtype: bool
        """
        try:
            WebDriverWait(self.driver, timeout).until(ec.text_to_be_present_in_element_value(locator, value))
            return True
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(value + '不在' + '元素 ' + str(locator) + ' 中')
            return False

    def text_to_be_present_in_text(self, locator, text, timeout=timeout):
        """
                判断字符串是否在text中

                :param timeout:
                :type timeout:
                :param locator: 例如：(By.ID, 'id')
                :type locator: tuple
                :param text: 要判断的字符串
                :type text: str
                :return: 是或否
                :rtype: bool
                """
        try:
            WebDriverWait(self.driver, timeout).until(ec.text_to_be_present_in_element(locator, text))
            return True
        except TimeoutException:
            screenshot.screenshot(self.driver)
            self.logger.exception(text + '不在' + '元素 ' + str(locator) + ' 中')
            return False

    def switch_to_default_content(self):
        """
        退出iframe
        """
        self.driver.switch_to.default_content()

    def switch_to_frame(self, selector, timeout=timeout):
        """
        切换iframe

        :param timeout:
        :type timeout:
        :param selector: css选择器，如id，name
        :type selector: str or WebElement
        :return:
        :rtype:
        """
        if isinstance(selector, str):
            try:
                WebDriverWait(self.driver, timeout).until(ec.frame_to_be_available_and_switch_to_it(selector))
            except TimeoutException:
                screenshot.screenshot(self.driver)
                self.logger.exception(selector + ': 元素不存在，进入项目列表iframe失败')
        elif isinstance(selector, WebElement):
            self.driver.switch_to.frame(selector)
        else:
            screenshot.screenshot(self.driver)
            raise ValueError('请传入正确的参数: str 或 WebElement')

    def click(self, locator):
        """点击事件"""
        try:
            self.element_to_be_clickable(locator)
            self.find_element(locator).click()
        except StaleElementReferenceException:
            self.find_element(locator).click()
        except ElementClickInterceptedException:
            self.execute_script('arguments[0].click();', self.find_element(locator))
        except AttributeError:
            screenshot.screenshot(self.driver)
            self.find_element(locator).click()

    def get_attribute(self, locator, attribute='value'):
        """获取属性值"""
        try:
            return self.find_element(locator).get_attribute(attribute)
        except AttributeError:
            screenshot.screenshot(self.driver)
            return ''

    def get_text(self, locator):
        """获取文本内容"""
        try:
            return self.find_element(locator).text
        except AttributeError:
            screenshot.screenshot(self.driver)
            return ''

    def send_keys(self, locator, value):
        """
        输入

        :param locator: 输入元素的loc
        :type locator: tuple
        :param value: 要输入的内容
        :type value: object
        :return: 输入的内容
        :rtype: str
        """
        self.find_element(locator).clear()
        self.find_element(locator).send_keys(value)
        return self.get_attribute(locator, 'value')

    def execute_script(self, script, *args):
        """执行js脚本"""
        self.driver.execute_script(script, *args)

    def upload(self, name='1pic'):
        """
        上传附件

        :param name: 附件类型
        :type name: str
        :return: 附件个数
        :rtype: dict
        """

        file_name = None
        if name == '1pic':
            file_name = '1.jpg'
        if name == '1pdf':
            file_name = 'pdf1.pdf'
        if name == '20files':
            file_name = '"1.jpg" "2.jpg" "3.jpg" "4.jpg" "5.jpg" "6.jpg" "7.jpg" "8.jpg" "9.jpg" "10.jpg" "11.jpg" ' \
                        '"12.jpg" "13.jpg" "14.jpg" "15.jpg" "16.jpg" "17.jpg" "18.bmp" "19.png" "pdf1.pdf"'
        if name == 'gt10m':
            file_name = 'gt10m.jpg'
        if name == 'gt10m_batch':
            file_name = '"pdf1.pdf" "pdf2.pdf" "pdf3.pdf" "pdf4.pdf" "pdf5.pdf" "pdf6.pdf" "pdf7.pdf" "pdf8.pdf"' \
                        ' "pdf9.pdf" "pdf10.pdf" "pdf11.pdf" "pdf12.pdf" "pdf13.pdf" "pdf14.pdf" "pdf15.pdf"' \
                        ' "pdf16.pdf" "pdf17.pdf" "pdf18.pdf"'
        if name == 'gt20files':
            file_name = '"1.jpg" "2.jpg" "3.jpg" "4.jpg" "5.jpg" "6.jpg" "7.jpg" "8.jpg" "9.jpg" "10.jpg" "11.jpg" ' \
                        '"12.jpg" "13.jpg" "14.jpg" "15.jpg" "16.jpg" "17.jpg" "18.bmp" "19.png" "pdf1.pdf" "mnlsa.jpg"'
        if name == 'not_pic':
            file_name = '"test_doc.docx" "test_mp4.mp4"'
        if name == 'pure':
            file_name = 'pure.jpg'
        if name == 'white':
            file_name = 'white.jpg'
        path = os.path.dirname(os.path.abspath('.')) + '\\picture\\upload\\' + file_name
        time.sleep(1)
        self.click((By.LINK_TEXT, '上传附件'))
        self.logger.info('点击上传附件按钮')
        # 这里等待弹窗完全出现
        time.sleep(1)
        # 输入附件名称
        pyautogui.typewrite(message=path, interval=0.5)
        self.logger.info('输入附件名称: ' + path)
        time.sleep(1)
        pyautogui.press('enter')
        # path = os.path.dirname(os.path.abspath('.')) + '\\common\\upload\\' + file_name
        # os.system(path)
        # time.sleep(1)
        # 单个文件大于10M：“图片大小应小于10M！”
        if name == 'gt10m':
            text = self.find_element((By.XPATH, '/html[1]/body[1]/div[3]/div[1]')).text
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            return {'msg': text}
        # 多个文件大于8M：“单次上传文件总大小不得超过8M！”
        if name == 'gt10m_batch':
            # 上传前附件个数
            count_before = self.get_count_files()
            self.logger.info('上传前个数: ' + str(count_before))
            # 提示信息
            locator_text = (By.XPATH, '/html[1]/body[1]/div[4]/div[2]')
            self.text_to_be_present_in_text(locator_text, '单次上传文件总大小不得超过8M！')
            text = self.find_element(locator_text).text
            self.click((By.XPATH, '/html[1]/body[1]/div[4]/div[3]/a[1]'))
            # 删除，使剩余附件小于等于8M
            for i in range(13):
                self.click(
                    (By.XPATH, '/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/table[1]/tbody[1]/tr[2]/td[5]/span[1]'))
                self.click((By.XPATH, '/html[1]/body[1]/div[4]/div[3]/a[1]'))
            # 保存
            self.click((By.XPATH, "//div[@class='filelistBoard']//a[@class='button saveBlue checkBtn']"))
            self.click((By.XPATH, "/html[1]/body[1]/div[6]/div[3]/a[1]"))
            # 这里不强行等待附件数量可能获取不准确
            time.sleep(1)
            count_after = self.get_count_files()
            self.logger.info('上传后个数: ' + str(count_after))
            count = count_after - count_before
            self.logger.info('上传个数: ' + str(count))
            msg = 'fail'
            if text == '单次上传文件总大小不得超过8M！' and count == 5:
                msg = text
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            return {'msg': msg, 'value': count}
        # 一次性上传多于20个文件：“单次上传不得超过20个文件！”
        if name == 'gt20files':
            text = self.find_element((By.XPATH, '/html[1]/body[1]/div[4]/div[2]')).text
            # 取消
            self.click((By.XPATH, '/html[1]/body[1]/div[4]/div[3]/a[2]'))
            # time.sleep(1)
            # x掉窗口
            self.click((By.XPATH, '/html[1]/body[1]/div[1]/div[1]/div[1]/span[1]/a[1]'))
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            return {'msg': text}
        # 非图片：“只允许上传图片或格式为pdf的文件！”
        if name == 'not_pic':
            text = self.find_element((By.XPATH, '/html[1]/body[1]/div[3]/div[1]')).text
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            return {'msg': text}
        # 纯色、白色：“存在纯色图片”
        if name == 'pure' or name == 'white':
            loc_text = (By.XPATH, '/html[1]/body[1]/div[3]/div[1]')
            self.text_to_be_present_in_text(loc_text, '存在纯色图片')
            text = self.find_element(loc_text).text
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            time.sleep(1)
            return {'msg': text}
        self.click((By.XPATH, '/html[1]/body[1]/div[6]/div[3]/a[1]'))
        # 这里不强行等待附件数量可能获取不准确
        time.sleep(1)
        # 上传后个数
        count = self.get_count_files()
        self.switch_to_default_content()
        self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
        return {'count': count}

    def switch_to_upload(self):
        """
        进入上传附件iframe
        """
        self.switch_to_default_content()
        loc_iframe_upload = (By.XPATH, '(//div[@class="layui-layer-content"])[last()]/iframe[1]')
        iframe = self.find_element(loc_iframe_upload)
        self.switch_to_frame(iframe)

    def upload_easy(self):
        """
        上传附件，使用input输入框，若使用autoit3或PyUserInput无法使用无界面浏览器，默认上传 1.jpg

        :return: 附件个数
        :rtype: int
        """

        self.switch_to_upload()
        pre = os.path.dirname(os.path.abspath('.')) + '\\picture\\upload\\'
        path = pre + '1.jpg'
        self.click((By.LINK_TEXT, '上传附件'))
        time.sleep(1)
        # 取消附件上传窗口，不需要在此窗口中选择附件
        pyautogui.press('esc')
        # 点击上传附件按钮后会在 //form[@id='ajform'] 中增加input，获取最后一个input上传
        self.find_element((By.XPATH, '//form[@id="ajform"]/input[last()]')).send_keys(path)
        self.click((By.LINK_TEXT, '确定'))
        # 这里不强行等待附件数量可能获取不准确
        time.sleep(1)
        # 上传后个数
        count = self.get_count_files()
        self.switch_to_default_content()
        # 关闭上传窗口
        loc_x = (By.XPATH, "(//a[@class='layui-layer-ico layui-layer-close layui-layer-close1'])[last()]")
        self.click(loc_x)
        return count

    def delete_file(self, xmid=None):
        """
        删除附件

        :param xmid: 项目id
        :type xmid: str
        :return: 是否删除成功
        :rtype:
        """
        # 有附件则删除
        if self.get_count_files():
            self.click((By.XPATH, '/html[1]/body[1]/div[1]/dl[1]/dd[1]/div[2]/div[1]/ul[1]/li[1]/i[1]'))
            # time.sleep(1)
            self.click((By.XPATH, '/html[1]/body[1]/div[4]/div[3]/a[1]'))
            # time.sleep(2)
            # 提示信息
            loc_text = (By.XPATH, '/html[1]/body[1]/div[3]/div[1]')
            self.text_to_be_present_in_text(loc_text, '删除成功！')
            try:
                res = self.find_element(loc_text).text
            except StaleElementReferenceException:
                res = self.find_element(loc_text).text
            # 页面附件个数
            count = self.get_count_files()
            file_names = self.get_file_names(xmid)
            msg = 'fail'
            if count == len(file_names) and res == '删除成功！':
                msg = 'success'
            self.switch_to_default_content()
            self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
            return {'msg': msg, 'value': count}
        self.switch_to_default_content()
        self.click((By.XPATH, '/html[1]/body[1]/div[15]/span[1]/a[1]'))
        return '没有附件'

    def get_count_files(self, timeout=timeout):
        """
        附件个数

        :return: 附件个数
        :rtype: int
        """
        lis = self.find_elements((By.CLASS_NAME, 'delPhoto'), timeout)
        if lis:
            return len(lis)
        return 0

    def remove_attribute(self, loc, attribute='readonly'):
        """
        删除 css 属性，默认删除 readonly

        :param loc: 元素loc
        :type loc: tuple
        :param attribute: 属性，如 readonly
        :type attribute: str
        :return:
        :rtype:
        """
        # 定位元素
        element = self.find_element(loc)
        # 删除readonly属性
        self.execute_script(f'arguments[0].removeAttribute("{attribute}")', element)

    def clear_date(self, locator):
        """清空日期"""

        self.click((By.CLASS_NAME, 'laydate-btns-clear'))
        self.click(locator)
        # 清空后必须点击下一个月才能选到当前月（为什么？）
        self.click((By.XPATH, "//i[@class='layui-icon laydate-icon laydate-next-m']"))

    def select_date(self, locator=None, option=1):
        """
        选择日期

        :param locator: 日期loc
        :type locator: tuple
        :param option: 日期
            0: 昨天
            1: 今天
            2: 明天
            3: 后天
        :type option: int
        :return:
        :rtype:
        """

        self.send_keys(locator, get_date(option))
        # # 选择昨天
        # if option == 0:
        #     self.send_keys(locator, yesterday)
        # # 选择今天
        # elif option == 1:
        #     # self.click((By.XPATH, "//span[@class='laydate-btns-now']"))
        #     self.send_keys(locator, today.strftime("%Y-%m-%d"))
        # # 选择明天
        # elif option == 2:
        #     # self.clear_date(locator)
        #     # self.click((By.XPATH, f"//td[contains(text(),'{tomorrow[-2:]}')]"))
        #     self.send_keys(locator, tomorrow)
        # # 选择后天
        # elif option == 3:
        #     # self.clear_date(locator)
        #     # self.click((By.XPATH, f"//td[contains(text(),'{the_day_after_tomorrow[-2:]}')]"))
        #     self.send_keys(locator, the_day_after_tomorrow)
        # else:
        #     raise ValueError('请输入数字：0 - 3')

    # def win_file(self, username='administrator', password='1qazZAQ!', xmid=None,
    #              nsrsbh_=nsrsbh):
    #     """
    #     连接服务器，执行cmd命令获取上传文件列表
    #
    #     :param nsrsbh_: 纳税人识别号
    #     :type nsrsbh_: str
    #     :param username: 账号
    #     :type username: str
    #     :param password: 密码
    #     :type password: str
    #     :param xmid: 项目 id
    #     :type xmid: str
    #     :return: 文件名
    #     :rtype: list
    #     """
    #     wintest = winrm.Session('http://' + self.ip + ':5985/wsman', auth=(username, password))
    #     cmd = get_cfg('server', 'cmd') + '%s\\%s\\101 & dir /b' % (nsrsbh_, xmid)
    #     self.logger.info('cmd: ' + cmd)
    #     ret = wintest.run_cmd(cmd)
    #     file_names = ret.std_out.decode().split('\r\n')
    #     self.logger.info('服务器附件: ' + str(file_names))
    #     return file_names

    def get_file_names(self, xmid, certificate_type=101, certificate_guid=None):
        """
        获取数据库汇总上传附件的名称

        :param certificate_guid: 证书guid
        :type certificate_guid: str
        :param certificate_type: 证书类型
            101：规划总平图
            16：国有土地使用权出（受）让合同
        :type certificate_type: int
        :param xmid: 项目id
        :type xmid: str
        :return: 附件名与xmid
        :rtype: list
        """
        conn = self.get_conn()
        with conn:
            cursor = conn.cursor()
            if not certificate_guid:
                cursor.execute("SELECT t.filepath FROM dbo.DJzstp t WHERE t.DJzstp_xmid = ? AND t.Zslx = ?",
                               (xmid, certificate_type))
            cursor.execute("SELECT t.filepath FROM dbo.DJzstp t WHERE t.DJzstp_xmid = ? AND t.Zslx = ? AND "
                           "t.ZsGuid = ?", (xmid, certificate_type, certificate_guid))
            rows = cursor.fetchall()
        file_names = []
        for row in rows:
            files = row[0].split('/')
            file_names.append(files[len(files) - 1])
        file_names.sort()
        self.logger.info('数据库附件: ' + str(file_names))
        return file_names

    def refresh(self):
        self.driver.refresh()


if __name__ == '__main__':
    base = Base(webdriver.Chrome())
